#!/usr/bin/python
# vim: set fileencoding=utf-8 :
# Positive Integer class. Depends on aInt.

from hexaInt import aInt

class posInt (aInt) :
    """Class Positive Integer.
    """
    def __init__(self, p1) :
        """ To instance x = Integer(p) where p ∈ Z and x ∈ Integer and x > 0.
        """
        self.val = aInt(p1)

    def __get__(self, o, t):
        """ Get
        """
        return PosInt(self.val)

    def __set__(self, o, v):
        """ Set
        """
        self.val = v

    def __getattribute__(self, key):
        """x.__getattribute__('name') <==> x.name
        Emulate type_getattro() in Objects/typeobject.c
        """
        v = object.__getattribute__(self, key)
        if hasattr(v, '__get__'):
            return v.__get__(None, self)
        return v

    def isPositiveInteger(self) :
        """ Check whether x ∈ Integer and x > 0.
        """
        return (self.isInteger() and (self.val > 0))

    def sieve(self, max):
        """ Takes in a number, and returns all primes between 2 and that max.
        """
        #Start with all of the numbers
        primes = range(posInt(2), posInt(max+1))
        primesPosInt = []
        #Start running through each number
        for i in primes :
            primesPosInt.append(posInt(i))
        for i in primesPosInt :
            #Start with double the number, and
            j = posInt(2)
            #remove all multiples
            k = i * j
            while k <= primesPosInt[-1]:
                k = i * j
                #As long as the current multiple of the number
                #is less than the last element in the list
                #If the multiple is in the list, take it out
                if k in primesPosInt:
                    primesPosInt.remove(k)
                j += posInt(1)
        return primesPosInt

    def primes(self):
        """Return a list of the prime factors for x ∈ posInt.
        """
        n = posInt(abs(self.val))
        one = posInt(1)
        if n == one: return [one]
        primes = self.sieve(int(n**0.5) + 1)
        prime_factors = []
        for p in primes:
            if p*p > n: break
            while n % p == 0:
                prime_factors.append(posInt(p))
                n //= p
        if n > 1: prime_factors.append(posInt(n))
        return prime_factors

